import { getCurrentInstance } from 'vue';

/**
 * 通用的组合式 API
 * 整合了 BEM 类名生成、节点查询、父组件数据获取等功能
 */
export const useCommon = () => {
   const instance = getCurrentInstance();
   if (!instance) {
      throw new Error('调用 useCommon 必须在 setup() 中');
   }
   const proxy = instance.proxy as any;

   /**
    * BEM 类名生成器
    * @param name 组件名称
    * @param fixed 固定类名数组
    * @param change 变化类名数组
    */
   const bem = (name: string, fixed?: string[], change?: string[]) => {
      const prefix = `uv-${name}--`;
      const classes: Record<string, boolean> = {};

      // 处理固定类名
      if (fixed?.length) {
         for (const item of fixed) {
            // 固定类名：始终存在，值来自当前组件实例同名字段的值
            const value = proxy?.[item];
            if (value !== undefined) {
               classes[prefix + value] = true;
            }
         }
      }
      // 处理变化类名
      if (change?.length) {
         for (const item of change) {
            // 变化类名：当对应字段为 truthy 时添加，例如 horizontal=true -> uv-xxx--horizontal
            const value = proxy?.[item];
            if (value) {
               classes[prefix + item] = true;
            }
         }
      }
      return (
         Object.keys(classes)
            // 支付宝、头条、飞书、百度小程序不支持数组类名，需转为空格分隔的字符串
            // #ifdef MP-ALIPAY || MP-TOUTIAO || MP-LARK || MP-BAIDU
            .join(' ')
         // #endif
      );
   };

   /**
    * 查询节点信息
    * 目前此方法在支付宝小程序中无法获取组件跟接点的尺寸，为支付宝的bug(2020-07-21)
    * 解决办法为在组件根部再套一个没有任何作用的view元素
    * @param selector 选择器
    * @param all 是否查询所有匹配的节点
    */
   const getRect = (selector: string, all?: boolean): Promise<any> => {
      return new Promise((resolve, reject) => {
         try {
            const query = uni.createSelectorQuery().in(instance);
            const method = all ? 'selectAll' : 'select';
            query[method](selector)
               .boundingClientRect((rect: any) => {
                  if (all) {
                     // 查询多个节点
                     resolve(Array.isArray(rect) && rect.length ? rect : []);
                  } else {
                     // 查询单个节点
                     resolve(rect || null);
                  }
               })
               .exec();
         } catch (error) {
            reject(error);
         }
      });
   };

   return {
      bem,
      getRect,
   };
};
